package org.uva.streambuilder;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;


import javax.swing.*;


public class BuilderPanel extends JPanel implements Runnable, MouseListener, 
        MouseMotionListener {
    
	int mx, my, cx, cy;
	int x, y, startx, starty;
	boolean running = true;
	boolean isMouseDraggingBox = false;
	Component currentObject;
	boolean isWiringMode = false;
	boolean isCreatingConnector = false;
	static int snap = 10;
	Component beginConnector, endConnector;
	
	Action enterWiringMode = new AbstractAction() {
		public void actionPerformed(ActionEvent e){
			isWiringMode = !isWiringMode;
			repaint();
		}
	};
	
	Action addModule = new AbstractAction() {
		public void actionPerformed(ActionEvent e){
			
			addModule();
			repaint();
		}

	};

	public void addModule()
	{
		ModuleComponent m = new ModuleComponent();
             
		Dimension size = m.getPreferredSize();
		m.setBounds(100, 100, size.width, size.height );
                
               
		this.add(m);
	}
	
	public BuilderPanel()
	{
		setPreferredSize(new Dimension(800, 600));
		setBackground(Color.darkGray);
		
		for (int x=0; x< 3; x++){
			addModule();
		}
		
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
		
		this.setDoubleBuffered(true);
		this.setLayout(null);
		
		
		this.getInputMap().put(KeyStroke.getKeyStroke("W"), "wiringMode");
		this.getActionMap().put("wiringMode", enterWiringMode);
		
		this.getInputMap().put(KeyStroke.getKeyStroke("A"), "addModule");
		this.getActionMap().put("addModule", addModule);
	
		Thread thread = new Thread(this);
		thread.start();
                
                
	}
	
    @Override
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		if (isWiringMode)
			g.fillRect(20, 20, 100, 100);
		
		drawConnector(g);
		drawConnectors(g);
	}
	
	public void run() {
		while (running){

			repaint();
			
			try {
				Thread.sleep(500);
				
			}catch (InterruptedException ex)
			{
			
				
			}
		}
	}
	
	public void drawConnectors( Graphics g)
	{
		for (Component module : this.getComponents())
		{
                    try {
			ModuleComponent src = (ModuleComponent) module;
			
			for ( ModuleComponent dest : src.outputList)
			{
				drawConnector( g, src, dest);
			}
                    } catch (ClassCastException c){}
		}
	}
	
	public void drawConnector( Graphics g, ModuleComponent src, ModuleComponent dest)
	{
		drawConnector(g, src.getOutputPostion(), dest.getInputPostion());
	}
	
        /** drawConnector 
         * 
         * @param g is the Graphics handle
         * @param src
         * @param dest
         */
	public void drawConnector( Graphics g, Point src, Point dest )
    {
		int sx = src.x;
		int sy = src.y;
		int endx = dest.x;
		int endy = dest.y;
		
		Graphics2D g2 = (Graphics2D)g;
    
    		int ymid = (cy-starty)/2 + starty;
    	
    		g2.setColor(Color.white);
    		
    		g2.drawLine(sx, sy, sx, ymid);
    		g2.drawLine(sx, ymid, endx, ymid);
    		g2.drawLine(endx, ymid, endx, endy);	
    		
    		repaint();
    	
    }
	
	public void drawConnector( Graphics g )
    {
	Graphics2D g2 = (Graphics2D)g;
    	if (isCreatingConnector)
    	{
    		int ymid = (cy-starty)/2 + starty;
    	
    		g2.setColor(Color.white);
    		
    		g2.drawLine(startx, starty, startx, ymid);
    		g2.drawLine(startx, ymid, cx, ymid);
    		g2.drawLine(cx, ymid, cx, cy);	
    		
    		repaint();
    	}
    }
	

	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
		this.requestFocus();
		
	}

	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	public void mousePressed(MouseEvent e) {
		mx = e.getX();
		my = e.getY();
		
		currentObject = this.getComponentAt(mx, my);
		if (currentObject != null 
                        && currentObject instanceof ModuleComponent 
                        && isWiringMode == false) 
                {
                    ModuleComponent sm = (ModuleComponent) currentObject;
                    if (e.getButton() == MouseEvent.BUTTON3)
                    {
                        sm.isSelected = !sm.isSelected;
                    }
			isMouseDraggingBox = true;
			Point p = currentObject.getLocation();
			x = p.x;
			y = p.y;
			this.setComponentZOrder(currentObject, 0);
			this.repaint();
		}
		
		if (currentObject != null && currentObject != this && isWiringMode == true)
		{
			isCreatingConnector = true;
			startx = mx;
			starty = my;
			beginConnector = currentObject;
		}
		
	}

	public void mouseReleased(MouseEvent e) {
		x = x - (x%snap);
		y = y - (y%snap);
		
                if (currentObject instanceof ModuleComponent)
                    currentObject.setLocation(x, y);
		
		isMouseDraggingBox = false;
		
		if (isCreatingConnector) {
			
			endConnector = this.getComponentAt(x, y);
			ModuleComponent end = (ModuleComponent) endConnector;
			ModuleComponent start = (ModuleComponent) beginConnector;
		
			start.outputList.add(end);
			end.inputList.add(start);
			
			isCreatingConnector = false;
			startx = 0; starty = 0;
		}
		
	}

	public void mouseDragged(MouseEvent e) {
            cx = e.getX();
            cy = e.getY();
    	
		if (isMouseDraggingBox ) {
		    int new_mx = e.getX();
		    int new_my = e.getY();

		    x += new_mx - mx;
		    y += new_my - my;

		    mx = new_mx;
		    my = new_my;
		         
		    currentObject.setLocation(x, y);
		    e.consume();
		}
		
	}

	public void mouseMoved(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
}
